home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
UUPC11QS.ARJ
/
MODEM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-07
|
28KB
|
718 lines
/*--------------------------------------------------------------------*/
/* m o d e m . c */
/* */
/* High level modem control routines for UUPC/extended */
/* */
/* Copyright (c) 1991 by Andrew H. Derbyshire */
/* */
/* Change history: */
/* 21 Apr 91 Create from dcpsys.c */
/*--------------------------------------------------------------------*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include "lib.h"
#include "arpadate.h"
#include "checktim.h"
#include "dcp.h"
#include "dcpsys.h"
#include "hlib.h"
#include "hostable.h"
#include "modem.h"
#include "script.h"
#include "security.h"
#include "ssleep.h"
#include "ulib.h"
#define MAX_MODEM 8 /* Max length of a modem name */
char *device = NULL; /*Public to show in login banner */
static char **answer, **initialize, **dropline, **ring, **connect;
static char *dialPrefix, *dialSuffix;
static INTEGER chardelay, dialTimeout, modemTimeout, scriptTimeout;
static INTEGER answerTimeout, inspeed;
static INTEGER gWindow, gPacket;
typedef enum {
MODEM_FIXEDSPEED,
MODEM_DIRECT,
MODEM_LAST
} MODEM_FLAGS;
static FLAGTABLE modemFlags[] = {
"direct", MODEM_DIRECT, B_UUIO,
"fixedspeed", MODEM_FIXEDSPEED, B_UUIO,
nil(char)
} ;
static boolean bmodemflag[MODEM_LAST];
static CONFIGTABLE modemtable[] = {
"answer", (char **) &answer, B_LIST | B_UUIO,
"answertimeout", (char **) &answerTimeout,B_INTEGER| B_UUIO,
"chardelay", (char **) &chardelay, B_INTEGER| B_UUIO,
"connect", (char **) &connect, B_LIST | B_UUIO,
"device", &device, B_TOKEN | B_UUIO | B_REQUIRED,
"dialprefix", &dialPrefix, B_STRING | B_UUIO | B_REQUIRED,
"dialsuffix", &dialSuffix, B_STRING | B_UUIO,
"dialtimeout", (char **) &dialTimeout, B_INTEGER| B_UUIO,
"gwindowsize", (char **) &gWindow, B_INTEGER| B_UUIO,
"gpacketsize", (char **) &gPacket, B_INTEGER| B_UUIO,
"initialize", (char **) &initialize, B_LIST | B_UUIO,
"hangup", (char **) &dropline, B_LIST | B_UUIO,
"modemtimeout", (char **) &modemTimeout, B_INTEGER| B_UUIO,
"options", (char **) bmodemflag, B_ALL | B_BOOLEAN,
"ring", (char **) &ring, B_LIST | B_UUIO,
"scripttimeout", (char **) &scriptTimeout,B_INTEGER| B_UUIO,
"inspeed", (char **) &inspeed, B_INTEGER| B_UUIO,
nil(char)
}; /* modemtable */
/*--------------------------------------------------------------------*/
/* Internal function prototypes */
/*--------------------------------------------------------------------*/
static boolean getmodem( const char *brand);
static boolean dial(char *number, const size_t speed);
static boolean sendlist( char **list, int timeout, int lasttimeout);
static boolean sendalt( char *string, int timeout);
static void autobaud( const size_t speed);
/*--------------------------------------------------------------------*/
/* Define current file name for references */
/*--------------------------------------------------------------------*/
currentfile();
/*--------------------------------------------------------------------*/
/* c a l l u p */
/* */
/* script processor - nothing fancy! */
/*--------------------------------------------------------------------*/
CONN_STATE callup()
{
char *exp;
int i;
size_t speed;
/*--------------------------------------------------------------------*/
/* Determine if the window for calling this system is open */
/*--------------------------------------------------------------------*/
if ( !callnow && equal(flds[FLD_CCTIME],"Never" ))
/* Don't update if we */
return CONN_INITIALIZE; /* never try calling */
time(&hostp->hstats->ltime); /* Save time of last attempt to call */
/*--------------------------------------------------------------------*/
/* Check the time of day and whether or not we should call now. */
/* */
/* If calling a system to set the clock and we determine the */
/* system clock is bad (we fail the sanity check of the last */
/* connected a host to being in the future), then we ignore the */
/* time check field. */
/*--------------------------------------------------------------------*/
if (!(callnow || checktime(flds[FLD_CCTIME],(time_t) 0)))
{
if ((*flds[FLD_PROTO] != '*') || /* Not setting clock? */
((hostp->hstats->ltime > hostp->hstats->lconnect) &&
(hostp->hstats->ltime > 630720000L )))
/* Clock okay? */
{ /* Yes--> Return */
hostp->hstatus = wrong_time;
return CONN_INITIALIZE;
}
} /* if */
/*--------------------------------------------------------------------*/
/* Announce we are trying to call the system */
/*--------------------------------------------------------------------*/
printmsg(1, "callup: calling \"%s\" via %s at %s on %s",
rmtname, flds[FLD_TYPE], flds[FLD_SPEED], arpadate());
hostp->hstatus = dial_failed; /* Assume failure in the dial */
speed = (size_t) atoi( flds[FLD_SPEED] );
if (speed < 300)
{
printmsg(0,"callup: Modem speed \"%s\" is invalid.",
flds[FLD_SPEED]);
return CONN_INITIALIZE;
}
/*--------------------------------------------------------------------*/
/* Get the modem information */
/*--------------------------------------------------------------------*/
if (!getmodem(flds[FLD_TYPE]))
return CONN_INITIALIZE;
/*--------------------------------------------------------------------*/
/* Dial the telephone */
/*--------------------------------------------------------------------*/
if (! dial(flds[FLD_PHONE],speed))
return CONN_DROPLINE;
/*--------------------------------------------------------------------*/
/* The modem is connected; now login the host */
/*--------------------------------------------------------------------*/
hostp->hstatus = script_failed; /* Assume failure */
for (i = FLD_EXPECT; i < kflds; i += 2) {
exp = flds[i];
printmsg(2, "expecting %d of %d \"%s\"", i, kflds, exp);
if (!sendalt( exp, scriptTimeout ))
{
printmsg(0, "SCRIPT FAILED");
return CONN_DROPLINE;
} /* if */
printmsg(2, "callup: sending %d of %d \"%s\"",
i + 1, kflds, flds[i + 1]);
sendstr(flds[i + 1]);
} /*for*/
return CONN_PROTOCOL;
} /*callup*/
/*--------------------------------------------------------------------*/
/* c a l l h o t */
/* */
/* Initialize processing when phone is already off the hook */
/*--------------------------------------------------------------------*/
CONN_STATE callhot( const BPS xspeed )
{
BPS speed;
if ( xspeed == 0)
speed = inspeed;
else
speed = xspeed;
/*--------------------------------------------------------------------*/
/* Open the serial port */
/*--------------------------------------------------------------------*/
if (E_inmodem == NULL)
{
printmsg(0,"callin: No modem name supplied for incoming calls!");
panic();
} /* if */
if (!getmodem(E_inmodem)) /* Initialize modem configuration */
panic(); /* Avoid loop if bad modem name */
/*--------------------------------------------------------------------*/
/* Open the communications port */
/*--------------------------------------------------------------------*/
if (openline(device, speed, bmodemflag[MODEM_DIRECT] ))
panic();
/*--------------------------------------------------------------------*/
/* Initialize stats */
/*--------------------------------------------------------------------*/
memset( &remote_stats, 0, sizeof remote_stats);
/* Clear remote stats for login */
time(&remote_stats.ltime); /* Remember time of last attempt conn */
remote_stats.calls ++ ;
return CONN_HOTLOGIN;
} /* callhot */
/*--------------------------------------------------------------------*/
/* c a l l i n */
/* */
/* Answer the modem in passive mode */
/*--------------------------------------------------------------------*/
CONN_STATE callin( const char *logintime )
{
char c; /* A character for input buffer */
int offset; /* Time to wait for telephone */
/*--------------------------------------------------------------------*/
/* Determine how long we can wait for the telephone, up to */
/* MAX_INT seconds. Aside from Turbo C limits, this insures we */
/* kick the modem once in a while. */
/*--------------------------------------------------------------------*/
if (logintime == NULL) /* Any time specified? */
offset = INT_MAX; /* No --> Run almost forever */
else { /* Yes --> Determine elapsed time */
int delta = 4096; /* Rate at which we change offset */
boolean split = FALSE;
if (!checktime(logintime,(time_t) 0)) /* Still want system up? */
return CONN_EXIT; /* No --> shutdown */
offset = 0; /* Wait until end of this minute */
while ( ((INT_MAX - delta) > offset ) && (delta > 0))
{
printmsg(4,"Current time is %s, offset is %d, offset is %d",
arpadate(), offset, delta);
if (checktime(logintime,(time_t) offset + delta))
offset += delta;
else
split = TRUE; /* Once we starting splitting, we
never stop */
if ( split )
delta /= 2;
} /* while */
} /* else */
/*--------------------------------------------------------------------*/
/* Open the serial port */
/*--------------------------------------------------------------------*/
if (E_inmodem == NULL)
{
printmsg(0,"callin: No modem name supplied for incoming calls!");
panic();
} /* if */
if (!getmodem(E_inmodem)) /* Initialize modem configuration */
panic(); /* Avoid loop if bad modem name */
if ((ring == NULL) || (inspeed == 0))
{
printmsg(0,"callin: Missing inspeed and/or ring values in modem \
configuration file.");
panic();
} /* if */
/*--------------------------------------------------------------------*/
/* Open the communications port */
/*--------------------------------------------------------------------*/
if (openline(device, inspeed, bmodemflag[MODEM_DIRECT]))
panic();
/*--------------------------------------------------------------------*/
/* Flush the input buffer of any characters */
/*--------------------------------------------------------------------*/
while (sread(&c ,1,0)); /* Discard trailing trash from modem
connect message */
/*--------------------------------------------------------------------*/
/* Initialize the modem */
/*--------------------------------------------------------------------*/
if (!sendlist( initialize, modemTimeout, modemTimeout))
{
printmsg(0,"callin: Modem failed to initialize");
panic();
}
/*--------------------------------------------------------------------*/
/* Wait for the telephone to ring */
/*--------------------------------------------------------------------*/
if (!sendlist( ring,modemTimeout, offset))
/* Did it ring? */
{
shutdown();
return CONN_INITIALIZE; /* No --> Return to caller */
}
if(!sendlist(answer, modemTimeout,answerTimeout))
/* Pick up the telephone */
{
printmsg(1,"callin: Modem failed to connect to incoming call");
shutdown();
return CONN_INITIALIZE;
}
/*--------------------------------------------------------------------*/
/* The modem is connected; now try to autobaud it */
/*--------------------------------------------------------------------*/
printmsg(14, "callin: got CONNECT");
autobaud(inspeed); /* autobaud the modem */
/*--------------------------------------------------------------------*/
/* Flush the input buffer of any other input characters */
/*--------------------------------------------------------------------*/
while (sread(&c ,1,0)); /* Discard trailing trash from modem
connect message */
memset( &remote_stats, 0, sizeof remote_stats);
/* Clear remote stats for login */
time(&remote_stats.ltime); /* Remember time of last attempt conn */
remote_stats.calls ++ ;
return CONN_LOGIN;
} /* callin */
/*--------------------------------------------------------------------*/
/* g e t m o d e m */
/* */
/* Read a modem configuration file */
/*--------------------------------------------------------------------*/
static boolean getmodem( const char *brand)
{
char filename[FILENAME_MAX];
static char modem[MAX_MODEM+1] = "";
FILE *fp;
CONFIGTABLE *tptr;
size_t subscript;
boolean success;
/*--------------------------------------------------------------------*/
/* Validate the modem name */
/*--------------------------------------------------------------------*/
if (strlen(brand) > MAX_MODEM)
{
printmsg(0,"getmodem: Invalid modem %s; must be %d characters or less",
brand, modem);
return FALSE;
}
if (equal(modem, brand)) /* Already initialized? */
return TRUE; /* Yes --> Don't process it again */
/*--------------------------------------------------------------------*/
/* Initialize the table */
/*--------------------------------------------------------------------*/
for (tptr = modemtable; tptr->sym != nil(char); tptr++)
if (tptr->bits & (B_TOKEN | B_STRING | B_LIST | B_CLIST))
*(tptr->loc) = nil(char);
for (subscript = 0; subscript < MODEM_LAST; subscript++)
bmodemflag[subscript] = FALSE;
chardelay = 00; /* Default is no delay between chars */
dialTimeout = 40; /* Default is 40 seconds to dial phone */
scriptTimeout = 30; /* Default is 30 seconds for script data*/
modemTimeout = 3; /* Default is 3 seconds for modem cmds */
gWindow = 0; /* Handle default in dcpgpkt */
gPacket = 0; /* Handle default in dcpgpkt */
/*--------------------------------------------------------------------*/
/* Open the modem configuration file */
/*--------------------------------------------------------------------*/
if (equaln(brand,"COM",3))
{
printmsg(0,"Modem type \"%s\" is invalid; Snuffles suspects \
your %s file is obsolete.", brand, SYSTEMS);
panic();
}
sprintf(filename,"%s/%s.MDM",confdir, brand);
if ((fp = FOPEN(filename, "r", TEXT)) == nil(FILE))
{
printmsg(0,"getmodem: Unable to locate configuration for %s",
brand);
printerr( filename );
return FALSE;
}
/*--------------------------------------------------------------------*/
/* We got the file open, now process it */
/*--------------------------------------------------------------------*/
printmsg(3,"getmodem: loading modem configuration file %s", filename);
success = getconfig(fp, MODEM_CONFIG, B_UUIO, modemtable, modemFlags);
fclose(fp);
if (!success)
return FALSE;
/*--------------------------------------------------------------------*/
/* Verify all required modem parameters were supplied */
/*--------------------------------------------------------------------*/
success = TRUE;
for (tptr = modemtable; tptr->sym != nil(char); tptr++) {
if ((tptr->bits & (B_REQUIRED | B_FOUND)) == B_REQUIRED)
{
printmsg(0, "getmodem: configuration parameter \"%s\" must be set.",
tptr->sym);
success = FALSE;
} /* if */
} /* for */
if ( success ) /* Good modem setup? */
strcpy( modem, brand); /* Yes --> Remember it for next time */
return success;
} /* getmodem */
/*--------------------------------------------------------------------*/
/* d i a l */
/* */
/* Generic modem dialer; only major limitation is that autoabaud */
/* strings are not configurable */
/*--------------------------------------------------------------------*/
static boolean dial(char *number, const size_t speed)
{
char buf[81];
/*--------------------------------------------------------------------*/
/* Open the serial port */
/*--------------------------------------------------------------------*/
if (openline(device, speed, bmodemflag[MODEM_DIRECT]))
return FALSE;
/*--------------------------------------------------------------------*/
/* Flush the input buffer of any characters */
/*--------------------------------------------------------------------*/
while (sread(buf,1,0)); /* Discard trailing trash from modem
connect message */
/*--------------------------------------------------------------------*/
/* Initialize the modem */
/*--------------------------------------------------------------------*/
if (!sendlist( initialize, modemTimeout, modemTimeout))
{
printmsg(0,"dial: Modem failed to initialize");
return FALSE;
}
/*--------------------------------------------------------------------*/
/* Setup the dial string and then dial the modem */
/*--------------------------------------------------------------------*/
strcpy(buf, dialPrefix);
strcat(buf, number);
if (dialSuffix != NULL)
strcat(buf, dialSuffix);
sendstr( buf ); /* Send the command to the telephone */
if (!sendlist(connect, modemTimeout, dialTimeout))
return FALSE;
printmsg(3, "dial: Modem reports connected");
time( &remote_stats.lconnect );
remote_stats.calls ++ ;
autobaud(speed); /* Reset modem speed, if desired */
/*--------------------------------------------------------------------*/
/* Report success to caller */
/*--------------------------------------------------------------------*/
return TRUE; /* Dial succeeded */
} /* dial */
/*--------------------------------------------------------------------*/
/* a u t o b a u d */
/* */
/* autobaud a modem which has just connected */
/*--------------------------------------------------------------------*/
static void autobaud( const size_t speed )
{
char buf[10];
ssleep(1); /* Allow modem port to stablize */
/*--------------------------------------------------------------------*/
/* Autobaud the modem if requested */
/*--------------------------------------------------------------------*/
if (!bmodemflag[MODEM_FIXEDSPEED])
{
size_t len = 0;
memset( buf, '\0', sizeof( buf )); /* Zero buffer */
while ((len < sizeof buf) && sread( &buf[len],1,0))
len = strlen( buf ); /* Get speed into buffer */
if (len > 5)
{
char *token; /* Pointer to buffer value */
token = strtok(buf,WHITESPACE);
if (strlen(token))
{
size_t new_speed = (unsigned) atoi(token);
if ((new_speed != speed) && (new_speed > 300))
{
printmsg(2, "autobaud: speed select %s", token);
SIOSpeed(atoi(token));
} /* if */
} /* if */
} /* if */
else
printmsg(3, "autobaud: unable to speed select, using %d", speed);
} /* if */
} /* autobaud */
/*--------------------------------------------------------------------*/
/* s h u t d o w n */
/* */
/* Terminate modem processing via hangup */
/*--------------------------------------------------------------------*/
void shutdown( void )
{
static boolean recurse = FALSE;
if ( !recurse )
{
recurse = TRUE;
hangup();
sendlist( dropline, modemTimeout, modemTimeout);
recurse = FALSE;
}
closeline();
}
/*--------------------------------------------------------------------*/
/* s e n d l i s t */
/* */
/* Send a NULL terminated list of send/expect strings */
/*--------------------------------------------------------------------*/
static boolean sendlist( char **list, int timeout, int lasttimeout)
{
boolean expect = TRUE;
if (list == NULL) /* Was the field supplied? */
return TRUE; /* No --> Must be optional, return */
/*--------------------------------------------------------------------*/
/* Run through the list, alternating expect and send strings */
/*--------------------------------------------------------------------*/
while( *list != NULL)
{
if (expect)
{
char *exp = strdup( *list );
boolean success;
checkref( exp );
success = sendalt( exp,
(*(++list) == NULL) ? lasttimeout : timeout);
free( exp );
if (!success)
return FALSE;
}
else
sendstr( *list++ );
expect = ! expect;
} /* while */
/*--------------------------------------------------------------------*/
/* If we made it this far, success is at hand; return to caller */
/*--------------------------------------------------------------------*/
return TRUE;
} /* sendlist */
/*--------------------------------------------------------------------*/
/* s e n d a l t */
/* */
/* Expect a string, with alternates */
/*--------------------------------------------------------------------*/
static boolean sendalt( char *exp, int timeout)
{
boolean ok = FALSE;
while (ok != TRUE) {
char *alternate = strchr(exp, '-');
if (alternate != nil(char))
*alternate++ = '\0';
ok = expectstr(exp, timeout);
if (ok) {
printmsg(2, "got that");
break;
}
if (alternate == nil(char)) {
return FALSE;
}
exp = strchr(alternate, '-');
if (exp != nil(char))
*exp++ = '\0';
printmsg(0, "sending alternate");
sendstr(alternate);
} /*while*/
return TRUE;
} /* sendalt */
/*--------------------------------------------------------------------*/
/* s l o w w r i t e */
/* */
/* Write characters to the serial port at a configurable */
/* snail's pace. */
/*--------------------------------------------------------------------*/
void slowwrite( char *s, int len)
{
swrite( s , len );
if (chardelay > 0)
ddelay(chardelay);
} /* slowwrite */
/*--------------------------------------------------------------------*/
/* G e t G W i n d o w */
/* */
/* Report the size of the allowed window for the "g" protocol */
/*--------------------------------------------------------------------*/
INTEGER GetGWindow( INTEGER maxvalue )
{
if ( (gWindow < 1 ) || (gWindow > maxvalue))
return maxvalue;
else
return gWindow;
} /* GetGWindow */
/*--------------------------------------------------------------------*/
/* G e t G P a c k e t */
/* */
/* Return the allowed packet size for the "g" procotol */
/*--------------------------------------------------------------------*/
INTEGER GetGPacket( INTEGER maxvalue )
{
if ( (gPacket < 1 ) || (gPacket > maxvalue))
return maxvalue;
else
return gPacket;
} /* GetGPacket */